/*
 * INET		An implementation of the TCP/IP protocol suite for the LINUX
 *		operating system.  INET is implemented using the  BSD Socket
 *		interface as the means of communication with the user level.
 *
 *		Definitions for the Interfaces handler.
 *
 * Version:	@(#)dev.h	1.0.10	08/12/93
 *
 * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
 *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *		Corey Minyard <wf-rch!minyard@relay.EU.net>
 *		Donald J. Becker, <becker@super.org>
 *		Alan Cox, <A.Cox@swansea.ac.uk>
 *		Bjorn Ekwall. <bj0rn@blox.se>
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 *
 *		Moved to /usr/include/linux for NET3
 */
#ifndef _LINUX_NETDEVICE_H
#define _LINUX_NETDEVICE_H

#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>

/* for future expansion when we will have different priorities. */
#define DEV_NUMBUFFS	3     // 数据包发送硬件缓冲队列数目
#define MAX_ADDR_LEN	7     // 硬件地址最大长度
#define MAX_HEADER	18    // 最大链路层首部长度

#define IS_MYADDR	1		/* address is (one of) our own	*/    // 远端发往本机的数据包
#define IS_LOOPBACK	2		/* address is for LOOPBACK	*/      // 本机发往本机的数据包
#define IS_BROADCAST	3		/* address is a valid broadcast	*/  // 远端或本机发送的广播数据包
#define IS_INVBCAST	4		/* Wrong netmask bcast not for us (unused)*/    // 无效的广播数据包
#define IS_MULTICAST	5		/* Multicast IP address */  // 多播包

/*
 *	We tag these structures with multicasts.
 */
// 链路层多播地址
struct dev_mc_list
{	
	struct dev_mc_list *next;
	char dmi_addr[MAX_ADDR_LEN];  // 具体的多播地址
	unsigned short dmi_addrlen;   // 多播地址长度
	unsigned short dmi_users;   // 该多播地址结构的使用数
};

/*
 * The DEVICE structure.
 * Actually, this whole structure is a big mistake.  It mixes I/O
 * data with strictly "high-level" data, and it has to know about
 * almost every data structure used in the INET module.  
 */ // 网络栈代码核心结构
struct device 
{

  /*
   * This is the first field of the "visible" part of this structure
   * (i.e. as seen by users in the "Space.c" file).  It is the name
   * the interface.
   */
  char			  *name;    // 设备名称

  /* I/O specific fields - FIXME: Merge these and struct ifmap into one */
  unsigned long		  rmem_end;		/* shmem "recv" end	*/    // rmem_end, rmem_start 设备读缓冲区空间
  unsigned long		  rmem_start;		/* shmem "recv" start	*/
  unsigned long		  mem_end;		/* sahared mem end	*/    // 设备总缓冲区首地址和尾地址
  unsigned long		  mem_start;		/* shared mem start	*/
  unsigned long		  base_addr;		/* device I/O address	*/    // 设备寄存器读写 I/O 基地址
  unsigned char		  irq;			/* device IRQ number	*/      // 设备使用的中断号

  /* Low-level status flags. */ // 设备所处状态
  volatile unsigned char  start,		/* start an operation	工作状态*/
                          tbusy,		/* transmitter busy	设备正忙于数据包发送，如果再有数据包发送，则需等待*/
                          interrupt;		/* interrupt arrived	软件正在进行设备中断处理*/

  struct device		  *next;  // 构成一个设备队列

  /* The device initialization function. Called only once. */
  /*
    设备初始化指针，对于系统静态定义的设备，在网络栈初始化时被调用对设备进行相应的初
    始化工作。而对于“动态插入”的设备（以动态模块方式加载的设备），则是在注册设备时
    （通过调用 register_netdev 函数），该指针指向的函数被调用初始化设备。对于网卡驱动程
    序编写而言，如果对应的设备需要初始化，则应将该指针指向对应的函数。
  */
  int			  (*init)(struct device *dev);

  /* Some hardware also needs these fields, but they are not part of the
     usual set specified in Space.c. */
  unsigned char		  if_port;		/* Selectable AUI, TP,..*/
  unsigned char		  dma;			/* DMA channel	设备所用的 DMA 通道号	*/

  struct enet_statistics* (*get_stats)(struct device *dev);   // 设备信息获取函数指针

  /*
   * This marks the end of the "visible" part of the structure. All
   * fields hereafter are internal to the system, and may change at
   * will (read: may be cleaned up at will).
   */

  /* These may be needed for future network-power-down code. */
  unsigned long		  trans_start;	/* Time (in jiffies) of last Tx	*/  // 该字段的设置功能用于传输超时计算(该版本未使用)
  unsigned long		  last_rx;	/* Time of last Rx	上次接收一个数据包的时间	*/

  unsigned short	  flags;	/* interface flags (a la BSD)	*/  // 设备状态，定义在 if.h 文件中，比如IFF_UP
  unsigned short	  family;	/* address family ID (AF_INET)	*/ // 表示设备所属的域协议，（均定义在 include/linux/socket.h），如AF_INET
  unsigned short	  metric;	/* routing metric (not used)	代价度量值，现在一般由来表示所经过的路由器数目。本版本没有使用该字段 */
  unsigned short	  mtu;		/* interface MTU value		*/
  unsigned short	  type;		/* interface hardware type 硬件类型，定义在if_arp.h中，比如ARPHRD_IEEE802*/
  unsigned short	  hard_header_len;	/* hardware hdr length	硬件首部长度*/
  void			  *priv;	/* pointer to private data	私有数据指针，一般使用在网卡驱动程序中用于指向自定义数据结构 */

  /* Interface address info. */
  unsigned char		  broadcast[MAX_ADDR_LEN];	/* hw bcast add 链路层硬件广播地址	*/
  unsigned char		  dev_addr[MAX_ADDR_LEN];	/* hw address	本设备硬件地址 */
  unsigned char		  addr_len;	/* hardware address length	硬件地址长度 */
  unsigned long		  pa_addr;	/* protocol address	本地IP地址	*/
  unsigned long		  pa_brdaddr;	/* protocol broadcast addr	网络层广播 IP 地址*/
  unsigned long		  pa_dstaddr;	/* protocol P-P other side addr	该字段仅使用在点对点网络中指对点 IP 地址 */
  unsigned long		  pa_mask;	/* protocol netmask	掩码	*/
  unsigned short	  pa_alen;	/* protocol address length	IP地址长度 */

  struct dev_mc_list	 *mc_list;	/* Multicast mac addresses	*/
  int			 mc_count;	/* Number of installed mcasts	*/
  
  struct ip_mc_list	 *ip_mc_list;	/* IP multicast filter chain    */
    
  /* For load balancing driver pair support */
  
  unsigned long		   pkt_queue;	/* Packets queued 缓存的待发送的数据包个数 */
  struct device		  *slave;	/* Slave device */
  

  /* Pointer to the interface buffers. */
  // 设备缓存的待发送的数据包，这些数据包由于某种原因之前没有成功发送，故缓存到 device
  // 结构的 buffs 数组指向的某个队列中。三个缓冲队列，分为三个优先级。
  struct sk_buff_head	  buffs[DEV_NUMBUFFS];

  /* Pointers to interface service routines. */
  /* 设备打开和关闭时调用的函数，网卡驱动程序需要实现这个函数，并将这个函数指针指向相
应的函数，从而当用户停止或启动网卡工作时进行适当的响应。 */
  int			  (*open)(struct device *dev);
  int			  (*stop)(struct device *dev);
  /* 数据包发送函数，网卡驱动程序中数据包发送核心函数，网络栈上层代码将调用该函数指针
指向的函数发送数据包，该函数硬件相关，主要将内核缓冲区中用户要发送数据复制到硬件
缓冲区中并启动设备将数据发送到物理传输介质上（如铜轴电缆或双绞线）。 */
  int			  (*hard_start_xmit) (struct sk_buff *skb,
					      struct device *dev);
  /* 硬件首部建立函数。这两个函数用于建立 MAC 首部。hard_header 一般仅在第一次建立硬件
首部时被调用，如果首次建立硬件首部失败（如暂时无法知道远端的硬件地址），则之后可
重复多次调用 rebuild_header 函数重新建立硬件首部。网卡驱动程序必须对这两个字段进行
适当初始化，即便是不使用 ARP 协议。 */
  int			  (*hard_header) (unsigned char *buff,
					  struct device *dev,
					  unsigned short type,
					  void *daddr,
					  void *saddr,
					  unsigned len,
					  struct sk_buff *skb);
  int			  (*rebuild_header)(void *eth, struct device *dev,
				unsigned long raddr, struct sk_buff *skb);
  /* 用于从接收到的数据包提取 MAC 首部中类型字段值，从而将数据包传送
给适当的协议处理函数进行处理。 */
  unsigned short	  (*type_trans) (struct sk_buff *skb,
					 struct device *dev);
#define HAVE_MULTICAST			
  /* 设置该设备的多播地址 */
  void			  (*set_multicast_list)(struct device *dev,
  					 int num_addrs, void *addrs);
#define HAVE_SET_MAC_ADDR  		 
  /* 如果设备支持改变其硬件地址，则该指针指向的函数即可被调用改变该设备对应的硬件地址。 */
  int			  (*set_mac_address)(struct device *dev, void *addr);
#define HAVE_PRIVATE_IOCTL
  /* 设置或获取设备的有关控制或统计信息。如可改变设备 MTU 值大小。 */
  int			  (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd);
#define HAVE_SET_CONFIG
  int			  (*set_config)(struct device *dev, struct ifmap *map);
  
};

/* packet_type结构表示网络层协议。每个网络层协议对应一个 packet_type 结构。内核支
持的所有网络层协议构成一个链表，系统变量 ptype_base（net/inet/dev.c）指向这个链表。
当系统接收到一个网络数据包时，通过 type_trans 指针指向函数得到数据包所使用的网络层
协议，之后遍历 ptype_base 指向的链表，比较 packet_type 结构中 type 字段与数据包所使用
的协议是否相符，如相符，则调用 packet_type 结构中 func 指针指向的函数，将数据包交给
其处理（即传往上层进行处理）。例如对应 IP 协议，对应的处理函数为 ip_rcv。 */
struct packet_type {
  unsigned short	type;	/* This is really htons(ether_type). 对应的网络层协议。该字段可取值如下（include/linux/if_ether.h）*/
  struct device *	dev;  // 数据包接收网络接口设备
  int			(*func) (struct sk_buff *, struct device *, // 协议处理函数。如对于 IP 协议，该指针指向 ip_rcv 函数。
				 struct packet_type *);
  void			*data;
  struct packet_type	*next;
};


#ifdef __KERNEL__

#include <linux/notifier.h>

/* Used by dev_rint */
#define IN_SKBUFF	1

extern volatile char in_bh;

extern struct device	loopback_dev;
extern struct device	*dev_base;
extern struct packet_type *ptype_base;


extern int		ip_addr_match(unsigned long addr1, unsigned long addr2);
extern int		ip_chk_addr(unsigned long addr);
extern struct device	*ip_dev_check(unsigned long daddr);
extern unsigned long	ip_my_addr(void);
extern unsigned long	ip_get_mask(unsigned long addr);

extern void		dev_add_pack(struct packet_type *pt);
extern void		dev_remove_pack(struct packet_type *pt);
extern struct device	*dev_get(char *name);
extern int		dev_open(struct device *dev);
extern int		dev_close(struct device *dev);
extern void		dev_queue_xmit(struct sk_buff *skb, struct device *dev,
				       int pri);
#define HAVE_NETIF_RX 1
extern void		netif_rx(struct sk_buff *skb);
/* The old interface to netif_rx(). */
extern int		dev_rint(unsigned char *buff, long len, int flags,
				 struct device * dev);
extern void		dev_transmit(void);
extern int		in_net_bh(void);
extern void		net_bh(void *tmp);
extern void		dev_tint(struct device *dev);
extern int		dev_get_info(char *buffer, char **start, off_t offset, int length);
extern int		dev_ioctl(unsigned int cmd, void *);

extern void		dev_init(void);

/* These functions live elsewhere (drivers/net/net_init.c, but related) */

extern void		ether_setup(struct device *dev);
extern int		ether_config(struct device *dev, struct ifmap *map);
/* Support for loadable net-drivers */
extern int		register_netdev(struct device *dev);
extern void		unregister_netdev(struct device *dev);
extern int 		register_netdevice_notifier(struct notifier_block *nb);
extern int		unregister_netdevice_notifier(struct notifier_block *nb);
/* Functions used for multicast support */
extern void		dev_mc_upload(struct device *dev);
extern void 		dev_mc_delete(struct device *dev, void *addr, int alen, int all);
extern void		dev_mc_add(struct device *dev, void *addr, int alen, int newonly);
extern void		dev_mc_discard(struct device *dev);
/* This is the wrong place but it'll do for the moment */
extern void		ip_mc_allhost(struct device *dev);
#endif /* __KERNEL__ */

#endif	/* _LINUX_DEV_H */
